package org.hepeng.workx.exception.translate;

import org.hepeng.workx.service.ServiceCallResult;
import org.hepeng.workx.service.error.DataAccessError;
import org.hepeng.workx.service.error.Error;
import org.hepeng.workx.service.error.JDBCError;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.dao.CannotSerializeTransactionException;
import org.springframework.dao.CleanupFailureDataAccessException;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.DeadlockLoserDataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.IncorrectUpdateSemanticsDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.dao.NonTransientDataAccessResourceException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.PermissionDeniedDataAccessException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.dao.QueryTimeoutException;
import org.springframework.dao.RecoverableDataAccessException;
import org.springframework.dao.TransientDataAccessException;
import org.springframework.dao.TransientDataAccessResourceException;
import org.springframework.dao.TypeMismatchDataAccessException;
import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.HeuristicCompletionException;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.InvalidIsolationLevelException;
import org.springframework.transaction.InvalidTimeoutException;
import org.springframework.transaction.NestedTransactionNotSupportedException;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionSuspensionNotSupportedException;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.TransactionTimedOutException;
import org.springframework.transaction.TransactionUsageException;
import org.springframework.transaction.UnexpectedRollbackException;

/**
 * @author he peng
 */
public class SCRSpringDAOExceptionTranslator extends SCRJdkExceptionTranslator
        implements SpringDAOExceptionTranslator<ServiceCallResult<? extends Error, Object>> {

    @Override
    public ServiceCallResult<? extends Error, Object> translate(CannotAcquireLockException ex) {
        return build(JDBCError.JDBC_ERROR ,
                spliceWithRootCauseMsg("on failure to aquire a lock during an update" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(CannotSerializeTransactionException ex) {
        return build(JDBCError.TRANSACTION_ERROR ,
                spliceWithRootCauseMsg("on complete a transaction failure in serialized mode due to update conflicts" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(CleanupFailureDataAccessException ex) {
        return build(JDBCError.JDBC_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(ConcurrencyFailureException ex) {
        return build(JDBCError.CONCURRENCY_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(DataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(DataAccessResourceFailureException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(DataIntegrityViolationException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(DataRetrievalFailureException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(DeadlockLoserDataAccessException ex) {
        return build(JDBCError.CONCURRENCY_ERROR ,
                spliceWithRootCauseMsg("the current process was a deadlock loser, and its transaction rolled back" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(DuplicateKeyException ex) {
        return build(JDBCError.DUPLICATE_KEY_ERROR ,
                spliceWithRootCauseMsg("violation of an primary key or unique constraint" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(EmptyResultDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(IncorrectResultSizeDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(IncorrectUpdateSemanticsDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(InvalidDataAccessApiUsageException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(InvalidDataAccessResourceUsageException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(NonTransientDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(NonTransientDataAccessResourceException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(OptimisticLockingFailureException ex) {
        return build(JDBCError.CONCURRENCY_ERROR ,
                spliceWithRootCauseMsg("an optimistic locking violation" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(PermissionDeniedDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR ,
                spliceWithRootCauseMsg("the underlying resource denied a permission to access a specific element" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(PessimisticLockingFailureException ex) {
        return build(JDBCError.CONCURRENCY_ERROR ,
                spliceWithRootCauseMsg("pessimistic locking violation" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(QueryTimeoutException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR ,
                spliceWithRootCauseMsg("query timeout" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(RecoverableDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(TransientDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(TransientDataAccessResourceException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(TypeMismatchDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR ,
                spliceWithRootCauseMsg("mismatch between Java type and database type" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(UncategorizedDataAccessException ex) {
        return build(DataAccessError.DATA_ACCESS_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(CannotCreateTransactionException ex) {
        return build(JDBCError.TRANSACTION_ERROR , spliceWithRootCauseMsg("transaction can't be created" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(HeuristicCompletionException ex) {
        return build(JDBCError.TRANSACTION_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(IllegalTransactionStateException ex) {
        return build(JDBCError.TRANSACTION_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(InvalidIsolationLevelException ex) {
        return build(JDBCError.TRANSACTION_ERROR , spliceWithRootCauseMsg("invalid isolation level " , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(InvalidTimeoutException ex) {
        return build(JDBCError.TRANSACTION_ERROR ,
                spliceWithRootCauseMsg("invalid timeout [" + ex.getTimeout() + "] " , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(NestedTransactionNotSupportedException ex) {
        return build(JDBCError.TRANSACTION_ERROR ,
                spliceWithRootCauseMsg("attempting to work with a nested transaction but nested transactions are not supported by the underlying backend" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(NoTransactionException ex) {
        return build(JDBCError.TRANSACTION_ERROR ,
                spliceWithRootCauseMsg("operation is attempted that relies on an existing transaction and there is no existing transaction" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(TransactionException ex) {
        return build(JDBCError.TRANSACTION_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(TransactionSuspensionNotSupportedException ex) {
        return build(JDBCError.TRANSACTION_ERROR ,
                spliceWithRootCauseMsg("attempting to suspend an existing transaction but transaction suspension is not supported by the underlying backend" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(TransactionSystemException ex) {
        return build(JDBCError.TRANSACTION_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(TransactionTimedOutException ex) {
        return build(JDBCError.TRANSACTION_ERROR , spliceWithRootCauseMsg("transaction has timed out" , ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(TransactionUsageException ex) {
        return build(JDBCError.TRANSACTION_ERROR , getRootCauseMsg(ex));
    }

    @Override
    public ServiceCallResult<? extends Error, Object> translate(UnexpectedRollbackException ex) {
        return build(JDBCError.TRANSACTION_ERROR ,
                spliceWithRootCauseMsg("attempt to commit a transaction resulted in an unexpected rollback" , ex));
    }
}
